home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Tools / idle / PyShell.py < prev    next >
Encoding:
Python Source  |  2000-03-08  |  23.2 KB  |  768 lines

  1. #! /usr/bin/env python
  2.  
  3. import os
  4. import sys
  5. import string
  6. import getopt
  7. import re
  8.  
  9. import linecache
  10. from code import InteractiveInterpreter
  11.  
  12. from Tkinter import *
  13. import tkMessageBox
  14.  
  15. from EditorWindow import EditorWindow, fixwordbreaks
  16. from FileList import FileList
  17. from ColorDelegator import ColorDelegator
  18. from UndoDelegator import UndoDelegator
  19. from OutputWindow import OutputWindow
  20. from IdleConf import idleconf
  21. import idlever
  22.  
  23. # We need to patch linecache.checkcache, because we don't want it
  24. # to throw away our <pyshell#...> entries.
  25. # Rather than repeating its code here, we save those entries,
  26. # then call the original function, and then restore the saved entries.
  27. def linecache_checkcache(orig_checkcache=linecache.checkcache):
  28.     cache = linecache.cache
  29.     save = {}
  30.     for filename in cache.keys():
  31.         if filename[:1] + filename[-1:] == '<>':
  32.             save[filename] = cache[filename]
  33.     orig_checkcache()
  34.     cache.update(save)
  35. linecache.checkcache = linecache_checkcache
  36.  
  37.  
  38. # Note: <<newline-and-indent>> event is defined in AutoIndent.py
  39.  
  40. #$ event <<plain-newline-and-indent>>
  41. #$ win <Control-j>
  42. #$ unix <Control-j>
  43.  
  44. #$ event <<beginning-of-line>>
  45. #$ win <Control-a>
  46. #$ win <Home>
  47. #$ unix <Control-a>
  48. #$ unix <Home>
  49.  
  50. #$ event <<history-next>>
  51. #$ win <Alt-n>
  52. #$ unix <Alt-n>
  53.  
  54. #$ event <<history-previous>>
  55. #$ win <Alt-p>
  56. #$ unix <Alt-p>
  57.  
  58. #$ event <<interrupt-execution>>
  59. #$ win <Control-c>
  60. #$ unix <Control-c>
  61.  
  62. #$ event <<end-of-file>>
  63. #$ win <Control-d>
  64. #$ unix <Control-d>
  65.  
  66. #$ event <<open-stack-viewer>>
  67.  
  68. #$ event <<toggle-debugger>>
  69.  
  70.  
  71. class PyShellEditorWindow(EditorWindow):
  72.  
  73.     # Regular text edit window when a shell is present
  74.     # XXX ought to merge with regular editor window
  75.  
  76.     def __init__(self, *args):
  77.         apply(EditorWindow.__init__, (self,) + args)
  78.         self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
  79.         self.text.bind("<<open-python-shell>>", self.flist.open_shell)
  80.  
  81.     rmenu_specs = [
  82.         ("Set breakpoint here", "<<set-breakpoint-here>>"),
  83.     ]
  84.  
  85.     def set_breakpoint_here(self, event=None):
  86.         if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
  87.             self.text.bell()
  88.             return
  89.         self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
  90.  
  91.  
  92. class PyShellFileList(FileList):
  93.  
  94.     # File list when a shell is present
  95.  
  96.     EditorWindow = PyShellEditorWindow
  97.  
  98.     pyshell = None
  99.  
  100.     def open_shell(self, event=None):
  101.         if self.pyshell:
  102.             self.pyshell.wakeup()
  103.         else:
  104.             self.pyshell = PyShell(self)
  105.             self.pyshell.begin()
  106.         return self.pyshell
  107.  
  108.  
  109. class ModifiedColorDelegator(ColorDelegator):
  110.  
  111.     # Colorizer for the shell window itself
  112.  
  113.     def recolorize_main(self):
  114.         self.tag_remove("TODO", "1.0", "iomark")
  115.         self.tag_add("SYNC", "1.0", "iomark")
  116.         ColorDelegator.recolorize_main(self)
  117.  
  118.     tagdefs = ColorDelegator.tagdefs.copy()
  119.     cconf = idleconf.getsection('Colors')
  120.  
  121.     tagdefs.update({
  122.         "stdin": cconf.getcolor("stdin"),
  123.         "stdout": cconf.getcolor("stdout"),
  124.         "stderr": cconf.getcolor("stderr"),
  125.         "console": cconf.getcolor("console"),
  126.         "ERROR": cconf.getcolor("ERROR"),
  127.     None: cconf.getcolor("normal"),
  128.     })
  129.  
  130.  
  131. class ModifiedUndoDelegator(UndoDelegator):
  132.  
  133.     # Forbid insert/delete before the I/O mark
  134.  
  135.     def insert(self, index, chars, tags=None):
  136.         try:
  137.             if self.delegate.compare(index, "<", "iomark"):
  138.                 self.delegate.bell()
  139.                 return
  140.         except TclError:
  141.             pass
  142.         UndoDelegator.insert(self, index, chars, tags)
  143.  
  144.     def delete(self, index1, index2=None):
  145.         try:
  146.             if self.delegate.compare(index1, "<", "iomark"):
  147.                 self.delegate.bell()
  148.                 return
  149.         except TclError:
  150.             pass
  151.         UndoDelegator.delete(self, index1, index2)
  152.  
  153. class ModifiedInterpreter(InteractiveInterpreter):
  154.  
  155.     def __init__(self, tkconsole):
  156.         self.tkconsole = tkconsole
  157.         locals = sys.modules['__main__'].__dict__
  158.         InteractiveInterpreter.__init__(self, locals=locals)
  159.  
  160.     gid = 0
  161.  
  162.     def execsource(self, source):
  163.         # Like runsource() but assumes complete exec source
  164.         filename = self.stuffsource(source)
  165.         self.execfile(filename, source)
  166.  
  167.     def execfile(self, filename, source=None):
  168.         # Execute an existing file
  169.         if source is None:
  170.             source = open(filename, "r").read()
  171.         try:
  172.             code = compile(source, filename, "exec")
  173.         except (OverflowError, SyntaxError):
  174.             self.tkconsole.resetoutput()
  175.             InteractiveInterpreter.showsyntaxerror(self, filename)
  176.         else:
  177.             self.runcode(code)
  178.  
  179.     def runsource(self, source):
  180.         # Extend base class to stuff the source in the line cache first
  181.         filename = self.stuffsource(source)
  182.         self.more = 0
  183.         return InteractiveInterpreter.runsource(self, source, filename)
  184.  
  185.     def stuffsource(self, source):
  186.         # Stuff source in the filename cache
  187.         filename = "<pyshell#%d>" % self.gid
  188.         self.gid = self.gid + 1
  189.         lines = string.split(source, "\n")
  190.         linecache.cache[filename] = len(source)+1, 0, lines, filename
  191.         return filename
  192.  
  193.     def showsyntaxerror(self, filename=None):
  194.         # Extend base class to color the offending position
  195.         # (instead of printing it and pointing at it with a caret)
  196.         text = self.tkconsole.text
  197.         stuff = self.unpackerror()
  198.         if not stuff:
  199.             self.tkconsole.resetoutput()
  200.             InteractiveInterpreter.showsyntaxerror(self, filename)
  201.             return
  202.         msg, lineno, offset, line = stuff
  203.         if lineno == 1:
  204.             pos = "iomark + %d chars" % (offset-1)
  205.         else:
  206.             pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
  207.                                                               offset-1)
  208.         text.tag_add("ERROR", pos)
  209.         text.see(pos)
  210.         char = text.get(pos)
  211.         if char and char in string.letters + string.digits + "_":
  212.             text.tag_add("ERROR", pos + " wordstart", pos)
  213.         self.tkconsole.resetoutput()
  214.         self.write("SyntaxError: %s\n" % str(msg))
  215.  
  216.     def unpackerror(self):
  217.         type, value, tb = sys.exc_info()
  218.         ok = type is SyntaxError
  219.         if ok:
  220.             try:
  221.                 msg, (dummy_filename, lineno, offset, line) = value
  222.             except:
  223.                 ok = 0
  224.         if ok:
  225.             return msg, lineno, offset, line
  226.         else:
  227.             return None
  228.  
  229.     def showtraceback(self):
  230.         # Extend base class method to reset output properly
  231.         text = self.tkconsole.text
  232.         self.tkconsole.resetoutput()
  233.         self.checklinecache()
  234.         InteractiveInterpreter.showtraceback(self)
  235.  
  236.     def checklinecache(self):
  237.         c = linecache.cache
  238.         for key in c.keys():
  239.             if key[:1] + key[-1:] != "<>":
  240.                 del c[key]
  241.  
  242.     debugger = None
  243.  
  244.     def setdebugger(self, debugger):
  245.         self.debugger = debugger
  246.  
  247.     def getdebugger(self):
  248.         return self.debugger
  249.  
  250.     def runcode(self, code):
  251.         # Override base class method
  252.         debugger = self.debugger
  253.         try:
  254.             self.tkconsole.beginexecuting()
  255.             try:
  256.                 if debugger:
  257.                     debugger.run(code, self.locals)
  258.                 else:
  259.                     exec code in self.locals
  260.             except SystemExit:
  261.                 if tkMessageBox.askyesno(
  262.                     "Exit?",
  263.                     "Do you want to exit altogether?",
  264.                     default="yes",
  265.                     master=self.tkconsole.text):
  266.                     raise
  267.                 else:
  268.                     self.showtraceback()
  269.                     if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
  270.                         self.tkconsole.open_stack_viewer()
  271.             except:
  272.                 self.showtraceback()
  273.                 if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
  274.                     self.tkconsole.open_stack_viewer()
  275.  
  276.         finally:
  277.             self.tkconsole.endexecuting()
  278.  
  279.     def write(self, s):
  280.         # Override base class write
  281.         self.tkconsole.console.write(s)
  282.  
  283.  
  284. class PyShell(OutputWindow):
  285.  
  286.     shell_title = "Python Shell"
  287.  
  288.     # Override classes
  289.     ColorDelegator = ModifiedColorDelegator
  290.     UndoDelegator = ModifiedUndoDelegator
  291.  
  292.     # Override menu bar specs
  293.     menu_specs = PyShellEditorWindow.menu_specs[:]
  294.     menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
  295.  
  296.     # New classes
  297.     from IdleHistory import History
  298.  
  299.     def __init__(self, flist=None):
  300.         self.interp = ModifiedInterpreter(self)
  301.         if flist is None:
  302.             root = Tk()
  303.             fixwordbreaks(root)
  304.             root.withdraw()
  305.             flist = PyShellFileList(root)
  306.  
  307.         OutputWindow.__init__(self, flist, None, None)
  308.  
  309.         import __builtin__
  310.         __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
  311.  
  312.         self.auto = self.extensions["AutoIndent"] # Required extension
  313.         self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
  314.  
  315.         text = self.text
  316.         text.configure(wrap="char")
  317.         text.bind("<<newline-and-indent>>", self.enter_callback)
  318.         text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
  319.         text.bind("<<interrupt-execution>>", self.cancel_callback)
  320.         text.bind("<<beginning-of-line>>", self.home_callback)
  321.         text.bind("<<end-of-file>>", self.eof_callback)
  322.         text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
  323.         text.bind("<<toggle-debugger>>", self.toggle_debugger)
  324.         text.bind("<<open-python-shell>>", self.flist.open_shell)
  325.         text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
  326.  
  327.         self.save_stdout = sys.stdout
  328.         self.save_stderr = sys.stderr
  329.         self.save_stdin = sys.stdin
  330.         sys.stdout = PseudoFile(self, "stdout")
  331.         sys.stderr = PseudoFile(self, "stderr")
  332.         sys.stdin = self
  333.         self.console = PseudoFile(self, "console")
  334.  
  335.         self.history = self.History(self.text)
  336.  
  337.     reading = 0
  338.     executing = 0
  339.     canceled = 0
  340.     endoffile = 0
  341.  
  342.     def toggle_debugger(self, event=None):
  343.         if self.executing:
  344.             tkMessageBox.showerror("Don't debug now",
  345.                 "You can only toggle the debugger when idle",
  346.                 master=self.text)
  347.             self.set_debugger_indicator()
  348.             return "break"
  349.         else:
  350.             db = self.interp.getdebugger()
  351.             if db:
  352.                 self.close_debugger()
  353.             else:
  354.                 self.open_debugger()
  355.  
  356.     def set_debugger_indicator(self):
  357.         db = self.interp.getdebugger()
  358.         self.setvar("<<toggle-debugger>>", not not db)
  359.  
  360.     def toggle_jit_stack_viewer( self, event=None):
  361.         pass # All we need is the variable
  362.  
  363.     def close_debugger(self):
  364.         db = self.interp.getdebugger()
  365.         if db:
  366.             self.interp.setdebugger(None)
  367.             db.close()
  368.             self.resetoutput()
  369.             self.console.write("[DEBUG OFF]\n")
  370.             sys.ps1 = ">>> "
  371.             self.showprompt()
  372.         self.set_debugger_indicator()
  373.  
  374.     def open_debugger(self):
  375.         import Debugger
  376.         self.interp.setdebugger(Debugger.Debugger(self))
  377.         sys.ps1 = "[DEBUG ON]\n>>> "
  378.         self.showprompt()
  379.         self.set_debugger_indicator()
  380.  
  381.     def beginexecuting(self):
  382.         # Helper for ModifiedInterpreter
  383.         self.resetoutput()
  384.         self.executing = 1
  385.         ##self._cancel_check = self.cancel_check
  386.         ##sys.settrace(self._cancel_check)
  387.  
  388.     def endexecuting(self):
  389.         # Helper for ModifiedInterpreter
  390.         ##sys.settrace(None)
  391.         ##self._cancel_check = None
  392.         self.executing = 0
  393.         self.canceled = 0
  394.  
  395.     def close(self):
  396.         # Extend base class method
  397.         if self.executing:
  398.             # XXX Need to ask a question here
  399.             if not tkMessageBox.askokcancel(
  400.                 "Kill?",
  401.                 "The program is still running; do you want to kill it?",
  402.                 default="ok",
  403.                 master=self.text):
  404.                 return "cancel"
  405.             self.canceled = 1
  406.             if self.reading:
  407.                 self.top.quit()
  408.             return "cancel"
  409.         return PyShellEditorWindow.close(self)
  410.  
  411.     def _close(self):
  412.         self.close_debugger()
  413.         # Restore std streams
  414.         sys.stdout = self.save_stdout
  415.         sys.stderr = self.save_stderr
  416.         sys.stdin = self.save_stdin
  417.         # Break cycles
  418.         self.interp = None
  419.         self.console = None
  420.         self.auto = None
  421.         self.flist.pyshell = None
  422.         self.history = None
  423.         OutputWindow._close(self) # Really EditorWindow._close
  424.  
  425.     def ispythonsource(self, filename):
  426.         # Override this so EditorWindow never removes the colorizer
  427.         return 1
  428.  
  429.     def short_title(self):
  430.         return self.shell_title
  431.  
  432.     def begin(self):
  433.         self.resetoutput()
  434.         self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
  435.                    (sys.version, sys.platform, sys.copyright,
  436.                     idlever.IDLE_VERSION))
  437.         try:
  438.             sys.ps1
  439.         except AttributeError:
  440.             sys.ps1 = ">>> "
  441.         self.showprompt()
  442.         import Tkinter
  443.         Tkinter._default_root = None
  444.  
  445.     def interact(self):
  446.         self.begin()
  447.         self.top.mainloop()
  448.  
  449.     def readline(self):
  450.         save = self.reading
  451.         try:
  452.             self.reading = 1
  453.             self.top.mainloop()
  454.         finally:
  455.             self.reading = save
  456.         line = self.text.get("iomark", "end-1c")
  457.         self.resetoutput()
  458.         if self.canceled:
  459.             self.canceled = 0
  460.             raise KeyboardInterrupt
  461.         if self.endoffile:
  462.             self.endoffile = 0
  463.             return ""
  464.         return line
  465.  
  466.     def isatty(self):
  467.         return 1
  468.  
  469.     def cancel_callback(self, event):
  470.         try:
  471.             if self.text.compare("sel.first", "!=", "sel.last"):
  472.                 return # Active selection -- always use default binding
  473.         except:
  474.             pass
  475.         if not (self.executing or self.reading):
  476.             self.resetoutput()
  477.             self.write("KeyboardInterrupt\n")
  478.             self.showprompt()
  479.             return "break"
  480.         self.endoffile = 0
  481.         self.canceled = 1
  482.         if self.reading:
  483.             self.top.quit()
  484.         return "break"
  485.  
  486.     def eof_callback(self, event):
  487.         if self.executing and not self.reading:
  488.             return # Let the default binding (delete next char) take over
  489.         if not (self.text.compare("iomark", "==", "insert") and
  490.                 self.text.compare("insert", "==", "end-1c")):
  491.             return # Let the default binding (delete next char) take over
  492.         if not self.executing:
  493. ##             if not tkMessageBox.askokcancel(
  494. ##                 "Exit?",
  495. ##                 "Are you sure you want to exit?",
  496. ##                 default="ok", master=self.text):
  497. ##                 return "break"
  498.             self.resetoutput()
  499.             self.close()
  500.         else:
  501.             self.canceled = 0
  502.             self.endoffile = 1
  503.             self.top.quit()
  504.         return "break"
  505.  
  506.     def home_callback(self, event):
  507.         if event.state != 0 and event.keysym == "Home":
  508.             return # <Modifier-Home>; fall back to class binding
  509.         if self.text.compare("iomark", "<=", "insert") and \
  510.            self.text.compare("insert linestart", "<=", "iomark"):
  511.             self.text.mark_set("insert", "iomark")
  512.             self.text.tag_remove("sel", "1.0", "end")
  513.             self.text.see("insert")
  514.             return "break"
  515.  
  516.     def linefeed_callback(self, event):
  517.         # Insert a linefeed without entering anything (still autoindented)
  518.         if self.reading:
  519.             self.text.insert("insert", "\n")
  520.             self.text.see("insert")
  521.         else:
  522.             self.auto.auto_indent(event)
  523.         return "break"
  524.  
  525.     def enter_callback(self, event):
  526.         if self.executing and not self.reading:
  527.             return # Let the default binding (insert '\n') take over
  528.         # If some text is selected, recall the selection
  529.         # (but only if this before the I/O mark)
  530.         try:
  531.             sel = self.text.get("sel.first", "sel.last")
  532.             if sel:
  533.                 if self.text.compare("sel.last", "<=", "iomark"):
  534.                     self.recall(sel)
  535.                     return "break"
  536.         except:
  537.             pass
  538.         # If we're strictly before the line containing iomark, recall
  539.         # the current line, less a leading prompt, less leading or
  540.         # trailing whitespace
  541.         if self.text.compare("insert", "<", "iomark linestart"):
  542.             # Check if there's a relevant stdin range -- if so, use it
  543.             prev = self.text.tag_prevrange("stdin", "insert")
  544.             if prev and self.text.compare("insert", "<", prev[1]):
  545.                 self.recall(self.text.get(prev[0], prev[1]))
  546.                 return "break"
  547.             next = self.text.tag_nextrange("stdin", "insert")
  548.             if next and self.text.compare("insert lineend", ">=", next[0]):
  549.                 self.recall(self.text.get(next[0], next[1]))
  550.                 return "break"
  551.             # No stdin mark -- just get the current line
  552.             self.recall(self.text.get("insert linestart", "insert lineend"))
  553.             return "break"
  554.         # If we're in the current input and there's only whitespace
  555.         # beyond the cursor, erase that whitespace first
  556.         s = self.text.get("insert", "end-1c")
  557.         if s and not string.strip(s):
  558.             self.text.delete("insert", "end-1c")
  559.         # If we're in the current input before its last line,
  560.         # insert a newline right at the insert point
  561.         if self.text.compare("insert", "<", "end-1c linestart"):
  562.             self.auto.auto_indent(event)
  563.             return "break"
  564.         # We're in the last line; append a newline and submit it
  565.         self.text.mark_set("insert", "end-1c")
  566.         if self.reading:
  567.             self.text.insert("insert", "\n")
  568.             self.text.see("insert")
  569.         else:
  570.             self.auto.auto_indent(event)
  571.         self.text.tag_add("stdin", "iomark", "end-1c")
  572.         self.text.update_idletasks()
  573.         if self.reading:
  574.             self.top.quit() # Break out of recursive mainloop() in raw_input()
  575.         else:
  576.             self.runit()
  577.         return "break"
  578.  
  579.     def recall(self, s):
  580.         if self.history:
  581.             self.history.recall(s)
  582.  
  583.     def runit(self):
  584.         line = self.text.get("iomark", "end-1c")
  585.         # Strip off last newline and surrounding whitespace.
  586.         # (To allow you to hit return twice to end a statement.)
  587.         i = len(line)
  588.         while i > 0 and line[i-1] in " \t":
  589.             i = i-1
  590.         if i > 0 and line[i-1] == "\n":
  591.             i = i-1
  592.         while i > 0 and line[i-1] in " \t":
  593.             i = i-1
  594.         line = line[:i]
  595.         more = self.interp.runsource(line)
  596.         if not more:
  597.             self.showprompt()
  598.  
  599.     def cancel_check(self, frame, what, args,
  600.                      dooneevent=tkinter.dooneevent,
  601.                      dontwait=tkinter.DONT_WAIT):
  602.         # Hack -- use the debugger hooks to be able to handle events
  603.         # and interrupt execution at any time.
  604.         # This slows execution down quite a bit, so you may want to
  605.         # disable this (by not calling settrace() in runcode() above)
  606.         # for full-bore (uninterruptable) speed.
  607.         # XXX This should become a user option.
  608.         if self.canceled:
  609.             return
  610.         dooneevent(dontwait)
  611.         if self.canceled:
  612.             self.canceled = 0
  613.             raise KeyboardInterrupt
  614.         return self._cancel_check
  615.  
  616.     def open_stack_viewer(self, event=None):
  617.         try:
  618.             sys.last_traceback
  619.         except:
  620.             tkMessageBox.showerror("No stack trace",
  621.                 "There is no stack trace yet.\n"
  622.                 "(sys.last_traceback is not defined)",
  623.                 master=self.text)
  624.             return
  625.         from StackViewer import StackBrowser
  626.         sv = StackBrowser(self.root, self.flist)
  627.  
  628.     def showprompt(self):
  629.         self.resetoutput()
  630.         try:
  631.             s = str(sys.ps1)
  632.         except:
  633.             s = ""
  634.         self.console.write(s)
  635.         self.text.mark_set("insert", "end-1c")
  636.  
  637.     def resetoutput(self):
  638.         source = self.text.get("iomark", "end-1c")
  639.         if self.history:
  640.             self.history.history_store(source)
  641.         if self.text.get("end-2c") != "\n":
  642.             self.text.insert("end-1c", "\n")
  643.         self.text.mark_set("iomark", "end-1c")
  644.         sys.stdout.softspace = 0
  645.  
  646.     def write(self, s, tags=()):
  647.         self.text.mark_gravity("iomark", "right")
  648.         OutputWindow.write(self, s, tags, "iomark")
  649.         self.text.mark_gravity("iomark", "left")
  650.         if self.canceled:
  651.             self.canceled = 0
  652.             raise KeyboardInterrupt
  653.  
  654. class PseudoFile:
  655.  
  656.     def __init__(self, shell, tags):
  657.         self.shell = shell
  658.         self.tags = tags
  659.  
  660.     def write(self, s):
  661.         self.shell.write(s, self.tags)
  662.  
  663.     def writelines(self, l):
  664.         map(self.write, l)
  665.  
  666.     def flush(self):
  667.         pass
  668.  
  669.     def isatty(self):
  670.         return 1
  671.  
  672.  
  673. usage_msg = """\
  674. usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
  675.  
  676. -c command  run this command
  677. -d          enable debugger
  678. -e          edit mode; arguments are files to be edited
  679. -s          run $IDLESTARTUP or $PYTHONSTARTUP before anything else
  680. -t title    set title of shell window
  681.  
  682. When neither -c nor -e is used, and there are arguments, and the first
  683. argument is not '-', the first argument is run as a script.  Remaining
  684. arguments are arguments to the script or to the command run by -c.
  685. """
  686.  
  687. def main():
  688.     cmd = None
  689.     edit = 0
  690.     debug = 0
  691.     startup = 0
  692.  
  693.     try:
  694.         opts, args = getopt.getopt(sys.argv[1:], "c:deist:")
  695.     except getopt.error, msg:
  696.         sys.stderr.write("Error: %s\n" % str(msg))
  697.         sys.stderr.write(usage_msg)
  698.         sys.exit(2)
  699.  
  700.     for o, a in opts:
  701.         if o == '-c':
  702.             cmd = a
  703.         if o == '-d':
  704.             debug = 1
  705.         if o == '-e':
  706.             edit = 1
  707.         if o == '-s':
  708.             startup = 1
  709.         if o == '-t':
  710.             PyShell.shell_title = a
  711.  
  712.     if not edit:
  713.         if cmd:
  714.             sys.argv = ["-c"] + args
  715.         else:
  716.             sys.argv = args or [""]
  717.  
  718.     for i in range(len(sys.path)):
  719.         sys.path[i] = os.path.abspath(sys.path[i])
  720.  
  721.     pathx = []
  722.     if edit:
  723.         for filename in args:
  724.             pathx.append(os.path.dirname(filename))
  725.     elif args and args[0] != "-":
  726.         pathx.append(os.path.dirname(args[0]))
  727.     else:
  728.         pathx.append(os.curdir)
  729.     for dir in pathx:
  730.         dir = os.path.abspath(dir)
  731.         if not dir in sys.path:
  732.             sys.path.insert(0, dir)
  733.  
  734.     global flist, root
  735.     root = Tk()
  736.     fixwordbreaks(root)
  737.     root.withdraw()
  738.     flist = PyShellFileList(root)
  739.  
  740.     if edit:
  741.         for filename in args:
  742.             flist.open(filename)
  743.  
  744.     shell = PyShell(flist)
  745.     interp = shell.interp
  746.     flist.pyshell = shell
  747.  
  748.     if startup:
  749.         filename = os.environ.get("IDLESTARTUP") or \
  750.                    os.environ.get("PYTHONSTARTUP")
  751.         if filename and os.path.isfile(filename):
  752.             interp.execfile(filename)
  753.  
  754.     if debug:
  755.         shell.open_debugger()
  756.     if cmd:
  757.         interp.execsource(cmd)
  758.     elif not edit and args and args[0] != "-":
  759.         interp.execfile(args[0])
  760.  
  761.     shell.begin()
  762.     root.mainloop()
  763.     root.destroy()
  764.  
  765.  
  766. if __name__ == "__main__":
  767.     main()
  768.